// Copyright (C) Calum Grant 2008

#include "cppscript"
#include "dynamic/extensions.hpp"
#include "wrap_cpp_container.hpp"

#include <vector>

static_call( register_pickle_type( cmp_array, array() ) );

using internal::nonroot_var;


namespace
{
	struct array_traits
	{
		typedef nonroot_var value_type;

		typedef std::vector<value_type, dynamic::allocator<value_type> > container;

		static var key(value_type & i) 
		{ 
			return i.get(); 
		}

		static var value(value_type & i) 
		{ 
			return i.get(); 
		}

		static var deref(const value_type & i) 
		{ 
			return i.get(); 
		}

		static void mark_reachable(const value_type & i, gc::garbage_collector & gc)
		{
			i.ref().impl().mark_reachable(gc);
		}

		static var pad_value() 
		{ 
			return var(); 
		}

		static const var & to_value(const var & v) 
		{ 
			return v; 
		}

		static const var_cmp_index comparison_index = cmp_array;

		static var back(const container & c) 
		{ 
			return c.back().get(); 
		}

		static var front(const container & c) 
		{ 
			return c.front().get(); 
		}

		static void pop_back(container & c) 
		{ 
			c.pop_back(); 
		}

		static void pickle(pickler & p, value_type & i)
		{
			p.write_object(i.ref());
		}

		static var unpickle(unpickler & p)
		{
			return p.read_object();
		}

		static const char * class_name() 
		{ 
			return "array"; 
		}

		static const char * iterator_class_name() 
		{ 
			return "array::iterator"; 
		}
	};
}

namespace dynamic
{
	namespace types
	{
		/// Implements an array variable.
		/** \ingroup  impl */
		typedef dynamic::internal::wrap_vector_container<array_traits> array_impl;
	}
}


var dynamic::array()
{
	return new types::array_impl();
}


var dynamic::array(const var &a0)
{
	var a = array();
	a.impl().reserve(1);
	a.push_back(a0);
	return a;
}


var dynamic::array(const var &a0, const var & a1)
{
	var a = array();
	a.impl().reserve(2);
	a.push_back(a0);
	a.push_back(a1);
	return a;
}


var dynamic::array(const var &a0, const var &a1, const var &a2)
{
	var a = array();
	a.impl().reserve(3);
	a.push_back(a0);
	a.push_back(a1);
	a.push_back(a2);
	return a;
}


var dynamic::array(const var &a0, const var &a1, const var &a2, const var & a3)
{
	var a = array();
	a.impl().reserve(4);
	a.push_back(a0);
	a.push_back(a1);
	a.push_back(a2);
	a.push_back(a3);
	return a;
}


var dynamic::array(const var &a0, const var &a1, const var &a2, const var & a3, const var & a4)
{
	var a = array();
	a.impl().reserve(5);
	a.push_back(a0);
	a.push_back(a1);
	a.push_back(a2);
	a.push_back(a3);
	a.push_back(a4);
	return a;
}


var dynamic::array(const var &a0, const var &a1, const var &a2, const var & a3, const var & a4, const var & a5)
{
	var a = array();
	a.impl().reserve(6);
	a.push_back(a0);
	a.push_back(a1);
	a.push_back(a2);
	a.push_back(a3);
	a.push_back(a4);
	a.push_back(a5);
	return a;
}


var dynamic::array(const var &a0, const var &a1, const var &a2, const var & a3, const var & a4, const var & a5, const var & a6)
{
	var a = array();
	a.impl().reserve(7);
	a.push_back(a0);
	a.push_back(a1);
	a.push_back(a2);
	a.push_back(a3);
	a.push_back(a4);
	a.push_back(a5);
	a.push_back(a6);
	return a;
}


var dynamic::array(const var &a0, const var &a1, const var &a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7)
{
	var a = array();
	a.impl().reserve(8);
	a.push_back(a0);
	a.push_back(a1);
	a.push_back(a2);
	a.push_back(a3);
	a.push_back(a4);
	a.push_back(a5);
	a.push_back(a6);
	a.push_back(a7);
	return a;
}


var dynamic::array(const var &a0, const var &a1, const var &a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8)
{
	var a = array();
	a.impl().reserve(9);
	a.push_back(a0);
	a.push_back(a1);
	a.push_back(a2);
	a.push_back(a3);
	a.push_back(a4);
	a.push_back(a5);
	a.push_back(a6);
	a.push_back(a7);
	a.push_back(a8);
	return a;
}


var dynamic::array(const var &a0, const var &a1, const var &a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8, const var & a9)
{
	var a = array();
	a.impl().reserve(10);
	a.push_back(a0);
	a.push_back(a1);
	a.push_back(a2);
	a.push_back(a3);
	a.push_back(a4);
	a.push_back(a5);
	a.push_back(a6);
	a.push_back(a7);
	a.push_back(a8);
	a.push_back(a9);
	return a;
}


var dynamic::fill_array(const var & size, const var & item)
{
	var a = array();
	int num = size.as_int();
	if(num<0) throw not_found(size);
	a.impl().reserve(num); 
	for(int i=0; i<num; ++i)
		a.push_back(item);

	return a;
}


var dynamic::array_from(const var & other)
{
	var a = array();
	foreach(i, other) a.push_back(i);
	return a;
}
